import random
import numpy
import csv

def getMirs (num):

    mirlist = []
    k = []
    
    i_list = []
        
    for i in range(num):
        k = random.sample(range(len(mirnas)), num)
        i_list.append(i)
        
        for j in k:
            mirlist.append(mirnas[j])

    return mirlist

    
        
def ScoreFunction ( pop , path , mir_scores ):
    
    curr_fitness = []
    
    for i in range(len(pop)):
        curr_fitness.append(Score(pop[i], path, mir_scores))
    
    return curr_fitness


def Score (mir_gene, path, mir_scores):   
                

    gene_score = 0                            

    for mir in mir_gene:
        
        sum_total = 0
        sum_pathway = 0
        
        for pathway, score in mir_scores[mir]:
        
            sum_total +=  score
        
            if pathway == path: sum_pathway += score
        
        gene_score += sum_pathway/(sum_total - sum_pathway)    
    
    
    gene_score = gene_score/len(mir_gene)
    
    return gene_score    



def Mutate (pop, mut_rate):  # Might be necessary to account for imbreeding, using the set function, intersect
    
    len_pop = len(pop)

    for i in range(len_pop):
        cur_gene = pop[i]
        
        cur_len = len(cur_gene)
        
        mut_list = []
        
        temp_index = []

        for j in range(cur_len):
            mut_list.append(random.random())
        
        for j in range(len(mut_list)): 
            if mut_list[ j ] < mut_rate:
                temp_index.append(j)    
        
        for j in temp_index:
            cur_gene.pop(j)
            cur_gene.append( getMirs( 1 ))

        pop[i] = cur_gene        
    
    return pop


def Insertion (pop, insert_rate):

    len_pop = len(pop)

    for i in range(len_pop):
        cur_gene = pop[i]
        
        cur_len = len(cur_gene)
        
        insert_list = []
        
        temp_index = []

        for j in range(cur_len):
            insert_list.append(random.random())
        
        for j in range( len( insert_list ) ): 
            if insert_list[ j ] < insert_rate:
                temp_index.append(j)    
        
        for j in temp_index:
            cur_gene.append( getMirs( 1 ))

        pop[i] = cur_gene        
    
    return pop


def Deletion (pop, del_rate):

    len_pop = len(pop)

    for i in range(len_pop):
        cur_gene = pop[i]
        
        cur_len = len(cur_gene)
        
        del_list = []
        
        temp_index = []

        for j in range(cur_len):
            del_list.append(random.random())
        
        for j in range( len( del_list ) ): 
            if del_list[ j ] < del_rate:
                temp_index.append(j)    
        
        for j in temp_index:
            cur_gene.pop(j)

        pop[i] = cur_gene        
    
    return pop


def StopCriteria (fitness, history, stall_gens):
    
    sum_fit =  numpy.sum(fitness)
    
    avg = sum_fit/len(fitness)

    
    stop_condition = 0        
    
    limit = 0.1    

    if len(history) < stall_gens:
        history.append(avg)
    else:
        del history[0]
        history.append(avg)
    
    if (numpy.std(history) < limit):
        stop_condition = 1

    return[history, stop_condition]
    


def Mate (pop, fitness, curr_path):
    
    prob = fitness
    prob = prob/numpy.sum(prob)
    
    kid = []
    i_list = []
    
    Num_Genes = len(pop)
    
    
    for i in range(Num_Genes/2):
        rdad = random.random()
        rmom = random.random()
        
        i_list.append(i)
        
        sum_rand = 0.0
        idad = 0
        
        while rdad > sum_rand:
            sum_rand += prob[idad]
            idad = idad + 1
        
        
        sum_rand = 0.0
        imom = 0
    
        while rmom > sum_rand:
            sum_rand += prob[imom]
            imom = imom + 1

        
        idad = idad - 1
        imom = imom - 1
        
        kid = Swap( pop[idad], pop[imom], curr_path)        If Score(pop[idad], curr_path) > Score(pop[imom], curr_path):
            del pop[imom]
            pop.append(kid)
        else:
            del pop[idad]
            pop.append(kid)

    return pop    


def Swap (dad, mom, curr_path):
    
    len_dad, len_mom = len(dad), len(mom)
    
    temp_dad = []
    temp_mom = [] 
    kid = []
        
    num_dad = random.randint(1, len(dad))
    num_mom = random.randint(1, len(mom))
    
    r_dad = random.sample(range(len_dad), num_dad)
    
    for i in r_dad:
        temp_dad.append(dad[i])
        del dad[i]

    r_mom = random.sample(range(len_mom), num_mom)
    
    for i in r_mom:
        temp_mom.append(mom[i])
        del mom[i]

    kid1 = temp_dad + mom
    kid2 =  temp_mom + dad
        
    if Score(kid1, curr_path) > Score(kid2, curr_path):
        kid = kid1
    else:
        kid = kid2
    
    kid = list(set(kid))

    return kid


    
mirlist_file = open("/Users/nithintumma/Desktop/miRNAs.csv", "rU")
mirna_file = open("/Users/nithintumma/Desktop/miRNA_ordered.csv", "rU")
scores_file = open("/Users/nithintumma/Desktop/score_ordered.csv", "rU")
pathways_file = open("/Users/nithintumma/Desktop/Pathways_ordered.csv", "rU")
    
mirnas = []
mirna_ordered = []
pathways_ordered = []
score_ordered = []
mir_scores = {}

Reader = csv.reader(mirlist_file, delimiter = "/")
for line in Reader:
    mirnas.append(line[0])

Reader = csv.reader(mirna_file, delimiter = "/")        
for line in Reader:    
    mirna_ordered.append(line[0])    

Reader = csv.reader(scores_file, delimiter = "/")        
for line in Reader:    
    score_ordered.append(line[0])

Reader = csv.reader(pathways_file, delimiter = "/")        
for line in Reader:    
    pathways_ordered.append(line[0])
        
score_ordered = [float(i) for i in score_ordered]

    
temp_mirs = []
for i in range(len(mirnas)):
    for j in range(len(mirna_ordered)):
        if mirnas[i] == mirna_ordered[j]:
            temp_mirs.append([pathways_ordered[j], score_ordered[j]])
    mir_scores[ mirnas[ i ] ] = temp_mirs
    temp_mirs = [ ]


        
population = []
fitness = []
history = []
    
curr_path = "hsa00010"

init_size = 10
max_gene_len = 5
stall_gens = 30

for i in range(max_gene_len):
    for j in range(init_size):
        population.append(getMirs(i+1))
    

ok = 1
stop_condition = 0
cnt = 0

while ok:
        
    fitness = ScoreFunction(population, curr_path, mir_scores)

    population = Mate(population, fitness, curr_path)

    population = Insertion(population, curr_path)

    population = Deletion(population, curr_path)

    history, stop_condition = StopCriteria(fitness, history, stall_gens)

    if stop_condition:
        ok = 0
        
    cnt = cnt + 1
        
    if cnt % 30 == 0:
        print("Current Best Score = " + str(max(fitness)))
        print("By: " + str(population[fitness.index(max(fitness))]))

print("Best Gene After " + str(cnt) + " = " + str(population[fitness.index(max(fitness))]))
        
    
